﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using FluentNHibernate.Cfg.Db;
using PinCity.ORM;
using System.Configuration;
using PinCity.Models.Repositories;
using PinCity.Localization;
using NHibernate.Context;
using NHibernate;

namespace PinCity
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(typeof(MvcApplication));

        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );

        }

        protected void Application_Start()
        {
            LocalizationManager.Initialize();

            logger.Info("Application starting...");

            logger.Info("Registering areas...");
            // Register areas (currently there are not custom areas)
            AreaRegistration.RegisterAllAreas();

            logger.Info("Registering global filters...");
            // Add filters to passed argument
            MvcApplication.RegisterGlobalFilters(GlobalFilters.Filters);

            logger.Info("Registering routes...");
            // Add routing rules to passed argument
            MvcApplication.RegisterRoutes(RouteTable.Routes);

            logger.Info("Initializing application data settings...");
            // Initialize application data, use default connection string
            this.InitializeAppData(ConfigurationManager.ConnectionStrings["default"].ConnectionString);

            logger.Info("Application started.");
        }

        /// <summary>
        /// Application data-related initialization. Used to configure PinCity.ORM.FluentManager
        /// and init every repository.
        /// </summary>
        /// <param name="connectionString">Connection string, that will be passed to database configuration object.</param>
        protected void InitializeAppData(string connectionString)
        {
            IPersistenceConfigurer databaseConfig = SQLiteConfiguration.Standard.ConnectionString(connectionString);
            FluentManager.DatabaseConfig = databaseConfig;
            FluentManager.Initialize(true);

            
            new RolesRepository().Initialize();
            new UsersRepository().Initialize();
            new PinRepository().Initialize();
            new PostsRepository().Initialize();
            new PinCommentsRepository().Initialize();
            new PostCommentsRepository().Initialize();
        }
        
        protected void Application_BeginRequest(
            object sender, EventArgs e)
        {
            this.BindSession(HttpContext.Current);
        }

        protected void Application_EndRequest(
            object sender, EventArgs e)
        {
            this.UnbindSession(HttpContext.Current);
        }

        /// <summary>
        /// Binds a session to the HttpContext, 
        /// the FluentManager.GetCurrentSession() 
        /// will return bound session.
        /// </summary>
        /// <param name="httpContext">Context to bind to. Usually current context.</param>
        protected void BindSession(HttpContext httpContext)
        {
            ISession newSession = FluentManager.OpenNewSession();
            ManagedWebSessionContext.Bind(httpContext, newSession);
        }

        /// <summary>
        /// Unbinds a session from given HttpContext object.
        /// Rolls back uncommited transaction.
        /// Flushes and closes session.
        /// </summary>
        /// <param name="httpContext"></param>
        protected void UnbindSession(HttpContext httpContext)
        {
            ISession session = ManagedWebSessionContext.Unbind(httpContext, FluentManager.SessionFactory);
            if (session != null)
            {
                if (session.Transaction != null && session.Transaction.IsActive)
                {
                    session.Transaction.Rollback();
                }
                else
                {
                    session.Flush();
                }
                session.Close();
            }
        }
    }
}